Eddie's Lessons
Beginners Programming
Recursive algorithms
Recusion is one of those less understood concepts in the hobiest programing world. There is rarly reason for a hobiest to utilize recursion exxcept as an acedemic exercise. One truly useful exception is walking an form of a tree, such as a directory tree. We will look at this a bit closer a bit later - first, just what is recursion?
I went to Wikipedia for a definition, where the following can be found:
A common method of simplification is to divide a problem into subproblems of the same type. As a computer programming technique, this is called divide and conquer and is key to the design of many important algorithms, as well as being a fundamental part of dynamic programming.
Virtually all programming languages in use today allow the direct specification of recursive functions and procedures. When such a function is called, the computer (for most languages on most stack-based architectures) or the language implementation keeps track of the various instances of the function (on many architectures, by using a stack, although other methods may be used). Conversely, every recursive function can be transformed into an iterative function by using a stack.
Any function that can be evaluated by a computer can be expressed in terms of recursive functions, without use of iteration, and conversely.
Some languages designed for logic programming and functional programming provide recursion as the only means of repetition directly available to the programmer. Such languages generally make tail recursion as efficient as iteration, letting programmers express other repetition structures (such as Scheme's (http://en.wikipedia.org/wiki/Scheme_programming_language) map and for) in terms of recursion.
Recursion is deeply embedded in the theory of computation, with the theoretical equivalence of recursive functions and Turing machines at the foundation of ideas about the universality of the modern computer.
An example of a recursive image:

See more about recursion on the Wikipedia site.
Ok, so I was left scratching my head a little. I bet you were too! That got pretty deep, but it seems to say that recursion is a method of looping functions iteratavly.
Some things just lend them selves to recursive functions. Year ago, in a C programming class I took, we had to write a solution to the Towers of Hanoi using recursion in as few lines of code as possible. Since C supports pointers our instructor was able to do it in just three lines of code. My solution was nine lines long.
As I mentioned earlier, one of the best places to use recursion is where you must traverse a node tree. A good example of this is reading the directory and file structure of a hard disk. I wrote a function that does this called Directory Tree (it is on my website LB Connection). At the end of this article you will fins a much simpler recursive style directory cataloging function called "dirsearch.bas".
Recursion came up as a recent topic on the Liberty Basic Forum where a community member challenged someone to convert a standard function with a looping mechanisum into a recursive function. The purpose of the function was to change any string into Title Case (where the first letter of each word is capitalized). If you are interested in that thread, check it out HERE.
It became instantly clear that most people did not understand the concept. All people who responded seemed to submit simpler, smaller versions of the original, but nothing recursive. Using recursion to solve the problem was overkill in this case, where a simple while loop was better suited to the application.
Recursive solutions exist though. I submitted two of them. This is the most elegant of the two:
print titleCase$("first last")
print titleCase$("george w. bush")
print titleCase$("salt lake city, utah")
end
function titleCase$(a$)
a$ = " " + a$
ln = len(a$)
titleCase$ = tC$(ln, 1, a$, "")
end function
function tC$(ln, pt, src$, buffer$)
nxtPt = pt + 1
if nxtPt > ln then
tC$ = buffer$
exit function
end if
b$ = mid$(src$,nxtPt,1)
if mid$(src$,pt,1) = " " and b$ <> " " then b$ = upper$(b$)
tC$ = tC$(ln, nxtPt, src$, buffer$ + b$)
end function
What you will notice about a recursive function is that you must keep track of where you are in the process, pass in a source string and return the result string back through the recursive calls. (In Liberty Basic you can also take advantage of the global property of arrays and use one of those for the result.) Also you must have some method of determining when the function needs to stop calling itself and return back out through the path it came.
The last point is critically important. If you fail to detect the end of the recursive call your program will stuck in an infinite regression - continually falling deeper and deeper into the regressive call until the computer becomes hopelessly CPU bound.
I like to think of recursion as being like those Chinese wooden nesting dolls that are hollow - one nests inside of another, inside of another and so on until the last one is just an inch high and they can't nest any further.

As I said - when you get to this last doll - you must be able to detect it and start backing out. Coming out of a recursive call is like unpacking the dolls. No processing happens on the way back out except to pass the result of the previous call back up to the next one coming out. In the end the final result in full is available when your code emerges from the last call to the recursive function.
The Liberty Basic Helpfile discusses recursive calls to functions. A really nice example is given in the form of finding a factorial - a great application for the concept. From Help File:
Liberty BASIC supports recursive subroutine and function calls. This means that a function can call itself. When it does this it makes a copy of itself, reusing its variable names. The values are not overwritten. It is important to place an evaluation statement inside a recursive function that causes the function to finish and return to the main code. Care should be taken to avoid creating an endlessly looping recursive function. The two examples below contains an "IF...THEN" evaluation that, when met, causes the function to stop calling itself and return control to the main program.
Here's an example of a recursive function that returns the factorial of a number. A factorial is obtained by taking a number and multiplying it in turn by each integer less than itself. The factorial of 5 is 5x4x3x2x1=120. The factorial of 7 is 7x6x5x4x3x2x1=5040. The numbers get big in a hurry after this. For example, the factorial of 15 is 1307674368000!!
'factorial
input "Compute factorial for?"; n
print factorial(n)
end
function factorial(a)
factorial = 1
if a > 1 then factorial = a*factorial(a-1)
end function
As mentioned above, here is the simple Directory Catalog function, a real world example of using recursion. The function was written several years ago for Liberty Basic 3, which had some unique limitations while using recursion. These introduced a little bit of extra complexity into the function. I have not tested the LB version 4 to see if these have been corrected, but I suspect they have been. Some experimentation with the code may result in a simpler function. I encourage experimentation.
Here is a sample run from function. It is followed by the source code:
c:\
--------------------------------------------------
..\Artios\ directory
..\Dell\ directory
..\documents and settings\ directory
..\documint\ directory
..\Empac85\ directory
..\FileNET\ directory
..\MSSQL7\ directory
..\Multimedia Files\ directory
..\Program Files\ directory
..\RCAdminCON\ directory
..\RECYCLER\ directory
..\System Volume Information\ directory
..\WebSite\ directory
..\WINDOWS\ directory
..\WUTemp\ directory
_NavCClt.Log 35.5 kb 08/24/04 04:42:40 PM
AUTOEXEC.BAT 0.0 kb 07/30/02 12:44:41 PM
boot.ini 0.2 kb 05/05/05 03:02:19 PM
COMLOG.txt 0.0 kb 05/06/05 07:19:11 PM
CONFIG.SYS 0.0 kb 07/30/02 12:44:41 PM
ffastun.ffa 4.6 kb 02/18/05 01:41:30 PM
ffastun.ffl 311.3 kb 02/18/05 01:41:30 PM
ffastun.ffo 532.5 kb 02/18/05 01:41:30 PM
ffastun0.ffx 987.1 kb 02/18/05 01:41:30 PM
IO.SYS 0.0 kb 07/30/02 12:44:41 PM
MSDOS.SYS 0.0 kb 07/30/02 12:44:41 PM
msisaund.ini 0.4 kb 12/27/04 02:11:27 PM
NTDETECT.COM 47.6 kb 05/05/05 02:40:41 PM
ntldr 250.0 kb 05/05/05 02:40:41 PM
pagefile.sys %402653.2 kb 05/06/05 07:11:06 PM
setupdl.log 71.7 kb 01/05/05 04:51:47 PM
setuppb.log 346.5 kb 01/05/05 04:39:39 PM
SetupPISDK.log 583.2 kb 01/05/05 04:50:59 PM
c:\Artios\
--------------------------------------------------
..\Keys\ directory
..\Viewer\ directory
artios.log 0.4 kb 07/30/02 01:05:40 PM
c:\Artios\Keys\
--------------------------------------------------
c:\Artios\Viewer\
--------------------------------------------------
..\ClientLib\ directory
..\InstLib\ directory
..\Program\ directory
..\ServerLib\ directory
Uninst.isu 24.4 kb 07/30/02 01:05:41 PM
'** FileTree Demonstration
'demonstrate the files command
'These arrays are required by the function - dimension the arrays we need
Dim Finfo$(10,3)
Dim FileTree$(2500)
MaxEntries = 2500
cls
[getFile]
print "Enter directory to catalog: ";
input Path$
if len(Path$) < 3 then [getFile]
[getEntries]
print "How many entries to return (10-2500): ";
input MaxEntries
if MaxEntries < 10 or MaxEntries > 2500 then [getEntries]
print
print "================================================="
Print "Cataloging: ";fileName$
Entries = FileTree(MaxEntries, 0, 1, Path$)
print
print "Complete"
print "Dumping the catalog..."
print "================================================="
print
For x = 1 to Entries
print FileTree$(x)
Next x
input a$
' -=-=-=-=-=-=-=-=-=-=- Functions -=-=-=-=-=-=-=-=-=-=-=-
Function FileTree(MaxEntries, CurrentEntry, CurrentLevel, Path$)
'About FileTree:
'---------------
'Function returns an formatted string array containing the directory
' and file tree from the specified path and down
'
'Prerequisites:
'-------------
'Requires that programmer setup an string array named FileTree$(x) to hold
' the formatted result of the FileTree function. It also requires a two
' dimensioned string array named Finfo$(10,3) to hold the results of the
' files statements. Arrays are global so they are not passed into the
' function.
'
'Arguments:
'----------
'MaxEntries is the maximum number of entries permitted in the array
' FileTree$(x). It is the value of x, the size of array.
'CurrentEntry is the current element in the array that was LAST
' populated. It is used as a pointer to load the next array element.
' When the function is first called this value is zero.
'CurrentLevel is the relative level in the directory structure
' that we are at compared with the original level called -
' this is always set to zero when the function is called.
'Path$ is the directory path to the directory we are creating
' a tree for.
'
'Return Value:
'-------------
'The function returns the latest entry that a value was written
' into. If after calling the function it returns with zero you
' know that no files or subdirectories exist.
txLen = 40
'First check for grievious errors
If Path$ = "" or MaxEntries = 0 Then
'We are done - can't go on
FileTree$(1) = "Error - Path is blank, or MaxEntries = 0: Can't continue"
CurrentEntry = 1
Else
'Now make sure we have not exceeded the MaxEntries Value
If CurrentEntry + 3 < MaxEntries Then
'Print the Directory Heading
FileTree$(CurrentEntry+1) = Left$(Path$, txLen+40)
FileTree$(CurrentEntry+2) = "--------------------------------------------------"
CurrentEntry = CurrentEntry + 3
'get the file info and stick it into the Finfo array
Files Path$, "*.*", Finfo$()
'items in Finfo$(0,?) - now have information we can use
qtyFiles = Val(Finfo$(0, 0))
qtySubDirs = Val(Finfo$(0, 1))
'If we have elected to include subdirs then sort & print them first
If qtySubDirs > 0 Then
'here we sort the subdirectories in the array by name
Sort Finfo$(), qtyFiles+1, qtyFiles+qtySubDirs, 0
For z = qtyFiles + 1 to qtyFiles + qtySubDirs
FileTree$(CurrentEntry) = Left$("..\" + Finfo$(z, 1) + "\" + Space$(txLen+6),txLen + 6) + _
" directory"
'Insure there is room for the next entry
CurrentEntry = CurrentEntry + 1
If CurrentEntry >= MaxEntries Then Exit For
Next z
End If
'Now we will process the files on this level (of recursion)
If qtyFiles > 0 Then
'reformat the file info (pad the file size so that sizes are right aligned)
For x = 1 to qtyFiles
Finfo$(x, 1) = Right$(" " + Finfo$(x, 1), 9)
Next x
'now sort the files in the array by name
'(Last argument in Sort command is sort field: 0 = Name, 1 = size)
Sort Finfo$(), qtyFiles, 1, 0
'now add the file information to the FileTree$ array
For x = qtyFiles to 1 step -1
kbyte$ = Using("#####.#",(Val(Finfo$(x, 1))/1000))
FileTree$(CurrentEntry) = Left$(Finfo$(x, 0) + Space$(txLen), txLen+1) + _
" "; kbyte$; " kb "; Finfo$(x, 2)
'Insure there is room for the next entry
CurrentEntry = CurrentEntry + 1
If CurrentEntry >= MaxEntries Then Exit For
Next x
End If
'Recurse any subdirectories if there are any.
If qtySubDirs > 0 Then
'We will plan to recurse for each sub-directory
'Unfortunatly the array with our subdirectories does
'not withstand recursion, so we must track our current
'endicy and also rebuild the array Finfo$ each time
'we return from a recursive call
x = 1
'Unfortunately control loops (FOR-NEXT and WHILE-WEND) do not
'perserve thier control information after recursion - must use
'explicit looping
[FileTree.Loop]
'Rebuild the array Finfo$:
'get the file info and stick it into the Finfo array
Files Path$, "*.*", Finfo$()
'items in Finfo$(0,?) now have information we can use
qtyFiles = Val(Finfo$(0, 0))
qtySubDirs = Val(Finfo$(0, 1))
'now sort the subdirectories in the array by name
'(Last element is Sort Field 0 = Name, 1 = size)
Sort Finfo$(), qtyFiles+1, qtyFiles+qtySubDirs, 0
'Build the new path to pass (Make sure it path ends in path delimiter
'before appending next layer path)
If Right$(Path$,1) <> "\" Then Path$ = Path$ + "\"
NewPath$ = Path$ + Finfo$(x+qtyFiles,1) + "\"
'call FileTree recursively
CurrentEntry = FileTree(MaxEntries, CurrentEntry, _
CurrentLevel+1, NewPath$)
'increment our counter that tracks which endicy we are on...
x = x + 1
If x <= qtySubDirs AND CurrentEntry+5 < MaxEntries Then GoTo [FileTree.Loop]
End If
End If
End If
FileTree = CurrentEntry
End Function
Eddie's Lessons
Beginners Programming